﻿using IM.Easy.Entity.Gen;
using IM.Easy.GenServices.Dtos;
using IM.Easy.GenServices.Dtos.Gen;
using IM.Easy.GenServices.IServices;
using Mapster;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Scriban;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using IM.Easy.Core.Extensions;
using IM.Easy.GenServices.Dtos.Gen.Vue3._0;
using IM.Easy.Core.Utils;
using Template = IM.Easy.GenServices.Dtos.Gen.Template;
using System.IO;
using Dm.util;

namespace IM.Easy.GenServices.Services
{
    public class GenService : IGenService
    {
        private readonly IWebHostEnvironment _env;
        public GenService(IWebHostEnvironment env)
        {
            _env = env;
        }

        /// <summary>
        /// 生成表信息
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public GenTable GenTableInfo(DbTableDto dto)
        {
            var genTable = new GenTable
            {
                Author = "IM.Easy",
                Name = dto.Name,
                Desc = dto.Desc,
                EntityName = dto.Name.ToPascalCase(),
                Options = GetOptions(dto),
            };
            var columns = GetColumns(dto.Columns);
            genTable.AuditProperty = GetAuditProperties(columns);
            genTable.Columns = GetBizProperties(columns);
            return genTable;
        }

        public GenModel GetGenModel(GenTableDto dto)
        {
            var model = new GenModel
            {

            };



            model.Templates =
            [
                new Template()
                {
                     TemplateName="实体层",
                     FileName = Path.Combine("Model", $"{dto.EntityName}.cs"),
                     TemplateFileName = "model.sbntxt",
                     Model = new  EntityTemplateModel
                      {
                            Using = ["SqlSugar", "IM.Easy.Core.Audit"],
                            Namespace = $"{dto.Options.Namespace}.Entity.{dto.Options.Module}",
                            Fields = dto.Columns,
                            AuditFields = dto.AuditColumns,
                            BizFields = dto.BusinessColumns,
                            EntityName = dto.EntityName,
                            TableName = dto.Name,
                            EntitySummary = dto.Desc,
                            BaseClass = dto.Options?.BaseClass
                      }
                },
                new Template()
                {
                    TemplateName="控制层",
                    FileName = Path.Combine("Controller", $"{dto.EntityName}Controller.cs"),
                    TemplateFileName = "controller.sbntxt",
                    Model =  new ControllerTemplateModel
                        {
                            Usings = ["IM.Easy.Infrastructure.Query",
                                "Microsoft.AspNetCore.Mvc",
                                $"{dto.Options.Namespace}.{dto.Options.Module}Services.Dtos",
                                $"{dto.Options.Namespace}.{dto.Options.Module}Services.IServices",
                                $"{dto.Options.Namespace}.Entity.{dto.Options.Module}"],
                            ClassName = $"{dto.Name}Controller",
                            Namespace = $"IM.Easy.Api.Controllers.{dto.Options.Module}",
                            EntityType = dto.EntityName,
                            IdType = dto.Columns.FirstOrDefault(s => s.IsPrimaryKey)?.DataType,
                            InterfaceName = $"I{dto.EntityName}Service",
                            ReturnType = dto.EntityName,
                        },
                },
                new Template()
                {
                    TemplateName="服务层",
                    FileName = Path.Combine("Services", $"{dto.EntityName}Service.cs"),
                    TemplateFileName = "service.sbntxt",
                    Model = new ServiceTemplateModel()
                    {
                        Usings = ["SqlSugar"
                                    , "IM.Easy.Core.Services"
                                    , "IM.Easy.Core.Utils"
                                    , "IM.Easy.Infrastructure.Query"
                                    , "IM.Easy.Core.Extensions"
                                    , $"IM.Easy.Entity.{dto.Options.Module}"
                                    , $"IM.Easy.{dto.Options.Module}Services.Dtos"
                                    , $"IM.Easy.{dto.Options.Module}Services.IServices"],
                        Namespace = $"{dto.Options.Namespace}.{dto.Options.Module}Services.Services",
                        ClassName = $"{dto.EntityName}Service",
                        EntityType = dto.EntityName,
                        PrimaryKey = dto.Columns.FirstOrDefault(s => s.IsPrimaryKey),
                        QueryColumns  = [.. dto.Columns.Where(s=>s.IsQueryable)],
                        InterfaceName = $"I{dto.EntityName}Service",
                        ReturnType = dto.EntityName
                    },
                },
                new Template()
                 {
                    TemplateName="服务接口层",
                    FileName= Path.Combine("IServices", $"I{dto.EntityName}Service.cs"),
                    TemplateFileName = "iservice.sbntxt",
                    Model = new InterfaceTemplateModel
                    {
                        Usings = [ "IM.Easy.Core.ServiceLifetime"
                                    , "IM.Easy.Core.Services"
                                    , "IM.Easy.Core.Utils"
                                    , "IM.Easy.Infrastructure.Query"
                                    , $"IM.Easy.Entity.{dto.Options.Module}"
                                    , $"IM.Easy.{dto.Options.Module}Services.Dtos"],
                        Namespace = $"{dto.Options.Namespace}.{dto.Options.Module}Services.IServices",
                        ClassName = $"I{dto.EntityName}Service",
                        EntityType = dto.EntityName,
                        IdType = dto.Columns.FirstOrDefault(s => s.IsPrimaryKey)?.DataType,
                        ReturnType = dto.EntityName
                    }
                },
                new Template()
                 {
                    TemplateName="数据传输层",
                    FileName= Path.Combine("Dto", $"{dto.EntityName}Dto.cs"),
                    TemplateFileName = "dto.sbntxt",
                    Model = new DtoTemplateModel
                        {
                            Usings = ["IM.Easy.Infrastructure.Query", "System.ComponentModel.DataAnnotations"],
                            Namespace = $"{dto.Options.Namespace}.{dto.Options.Module}Services.Dtos",
                            Fields = dto.Columns,
                            DtoClassName = $"{dto.Name}Dto",
                            DtoClassSummary = $"{dto.Desc}dto",
                            QueryDtoClassName = $"{dto.Name}QueryDto",
                            QueryDtoClassSummary = $"{dto.Desc}查询实体",
                            QueryFields = dto.Columns.Where(s => s.IsQueryable).ToList()
                        },
                },
                new Template()
                {
                    TemplateName="api接口",
                    FileName= Path.Combine("vue3.0", "api",$"{dto.EntityName.ToLower()}.js"),
                    TemplateFileName = Path.Combine("vue3.0","api.sbntxt") ,
                    Model = new ApiTemplateModel
                    {
                         Base = dto.EntityName.ToLower(),
                         EntityName = dto.EntityName,
                         Module = dto.Options.Module
                    }
                },
                new Template()
                {
                    TemplateName="前端页面",
                    FileName= Path.Combine("vue3.0","views", $"index.vue"),
                    TemplateFileName = Path.Combine("vue3.0","index.sbntxt") ,
                    Model =new VueIndexTemplateModel
                      {
                                Columns = dto.Columns,
                                QueryColumns = [.. dto.Columns.Where(s=>s.IsQueryable)],
                                EditColumns = [.. dto.Columns.Where(s=>s.IsEditable)],
                                DictionaryColumns = [.. dto.Columns.Where(s=>!string.IsNullOrEmpty(s.DictType))],
                                EntityName = dto.EntityName,
                                PrimaryKey = dto.Columns.FirstOrDefault(s=>s.IsPrimaryKey)?.Prop,
                                ApiPath = $"@/api/{dto.Options.Module.ToLower()}/{dto.EntityName.ToLower()}.js",
                                Func = dto.Options.Func,
                                Ascending = dto.Options.Ascending,
                                SortField = dto.Options.SortField,
                        }
                }
            ];

            return model;
        }

        /// <summary>
        /// 获取代码
        /// </summary>
        public MemoryStream Gen(GenModel model)
        {
            var destFloder = Path.Combine(_env.WebRootPath, "Code", DateTime.Now.ToString("yyyyMMddHHmmss"));
            var targetDirectory = Path.Combine(_env.ContentRootPath, "Code");
            foreach (var template in model.Templates)
            {
                GenCode(template.TemplateFileName, Path.Combine(destFloder, template.FileName), template.Model);
            }
            var stream = FileUtils.ZipDirectory(destFloder, targetDirectory);
            return stream;
        }

        /// <summary>
        /// 获取预览代码
        /// </summary>
        public List<CodeFileInfo> GetPreviewCode(GenModel model)
        {
            var codeFiles = new List<CodeFileInfo>();
            foreach (var template in model.Templates)
            {
                var code = GenCode(template.TemplateFileName, template.Model);
                var codeFile = new CodeFileInfo
                {
                    Content = code,
                    FileName = Path.GetFileName(template.FileName),
                    FileType = Path.GetExtension(template.FileName),
                    RelativePath = template.FileName,
                    Template = template,
                };
                codeFiles.Add(codeFile);
            }
            return codeFiles;
        }


        #region 生成不同模块的代码
        private void GenCode(string templatePath, string path, object model)
        {
            var code = GenCode(templatePath, model);
            // 从完整路径获取目录部分
            string directoryPath = Path.GetDirectoryName(path);

            // 检查目录部分是否为空并创建目录
            if (!string.IsNullOrEmpty(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }
            File.WriteAllText(path, code);
        }

        /// <summary>
        /// 生成代码文本
        /// </summary>
        /// <param name="templatePath"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        private string GenCode(string templatePath, object model)
        {
            // 读取模板
            templatePath = Path.Combine(_env.WebRootPath, "templates", templatePath);
            var templateContent = File.ReadAllText(templatePath);

            // 编译模板
            var template = Scriban.Template.Parse(templateContent);
            string baseDirectory = _env.ContentRootPath;
            var result = template.Render(model);
            return result;
        }

        /// <summary>
        /// 生成vue3.0代码
        /// </summary>
        private string GenerateVue3(VueIndexTemplateModel model)
        {
            // 读取模板
            var templatePath = Path.Combine("vue3.0", "index.sbntxt");
            string filePath = Path.Combine(_env.ContentRootPath, "Code", "Vue", $"index.vue");
            GenCode(templatePath, filePath, model);
            return filePath;
        }
        #endregion


        private List<GenTableColumn> GetColumns(List<DbColumnInfo> dbColumns)
        {
            int order = 0;
            var columns = new List<GenTableColumn>();
            foreach (var dbCol in dbColumns)
            {
                var col = new GenTableColumn()
                {
                    ColumnName = dbCol.DbColumnName,
                    Description = dbCol.ColumnDescription,
                    IsPrimaryKey = dbCol.IsPrimarykey,
                    PhysicalType = dbCol.DataType,
                    //TableId = genTable.TableId,
                    //TableName = genTable.TableName,
                    DataType = GetCSharpDatatype(dbCol.DataType),
                    FieldName = GetCSharpField(dbCol.DbColumnName),
                    IsRequired = !dbCol.IsNullable,
                    IsIncrement = dbCol.IsIdentity,
                    IsInsertable = !dbCol.IsIdentity,//|| GenConstants.inputDtoNoField.Any(f => f.Contains(column.DbColumnName, StringComparison.OrdinalIgnoreCase)),//非自增字段都需要插入
                    IsEditable = true,
                    IsQueryable = false,
                    IsVisible = true,
                    IsExportable = true,
                    DisplayType = "input",//GenConstants.HTML_INPUT,
                    Order = order++,
                };
                columns.Add(col);
            }
            return columns;
        }

        private GenTableOption GetOptions(DbTableDto dbTableDto)
        {
            var options = new GenTableOption()
            {
                Namespace = "IM.Easy",
                Module = "System",
                Business = dbTableDto.Name,
                Func = ["del", "add", "update", "view"]
            };
            return options;
        }

        private List<GenAuditProperty> GetAuditProperties(List<GenTableColumn> columns)
        {
            var auditProperties = new List<GenAuditProperty>();
            foreach (var col in columns)
            {
                // 判断是否为审计字段（可根据你的审计工具类或字段名判断）
                if (AuditFieldUtils.IsAuditFieldName(col.FieldName))
                {
                    auditProperties.Add(new GenAuditProperty
                    {
                        Id = Guid.NewGuid(),
                        TableId = col.TableId,
                        ColumnName = col.ColumnName,
                        Description = col.Description,
                        PhysicalType = col.PhysicalType,
                        DataType = col.DataType,
                        FieldName = col.FieldName,
                        Enable = true
                    });
                }
            }
            return auditProperties;
        }

        private List<GenTableColumn> GetBizProperties(List<GenTableColumn> columns)
        {
            var bizProperties = new List<GenTableColumn>();
            foreach (var col in columns)
            {
                if (!AuditFieldUtils.IsAuditFieldName(col.FieldName))
                {
                    bizProperties.Add(col);
                }
            }
            return bizProperties;
        }
        private string GetCSharpDatatype(string sDatatype)
        {
            sDatatype = sDatatype.ToLower();
            string sTempDatatype = sDatatype switch
            {
                "int" or "number" or "integer" or "smallint" => "int",
                "bigint" => "long",
                "tinyint" => "byte",
                "numeric" or "real" or "float" => "float",
                "decimal" or "numer(8,2)" or "numeric" => "decimal",
                "bit" => "bool",
                "date" or "datetime" or "datetime2" or "smalldatetime" or "timestamp" => "DateTime",
                "money" or "smallmoney" => "decimal",
                _ => "string",
            };
            return sTempDatatype;
        }

        private string GetCSharpField(string columnName)
        {
            return columnName.ToPascalCase();
        }
    }
}
